#include <assert.h>
#include <allegro.h>
#include "game.h"
#include "main.h"
#include "world/map.h"
#include "network.h"
#include "logic.h"
#include "generator/dungeon.h"
#include "util/log.h"
#include "util/mt.h"
#include "common/common_game.h"

#define MAX_ENEMIES

StoCmessage netmessage; // For communications to clients
CtoSmessage received;  // For communications to clients

Game the_game; // TODO: kill this obnoxious global variable

void game_damage_handler (int time, Coord where, int attacker, int victim, int weapon, int damage);

void game_init ()
{
	common_game_init ();
	damage_handler = &game_damage_handler; // Set handler for logic
	log_debug ("game_init() done");
}

// Creates a map, maybe?
void game_seed (unsigned long seed, int n_characters)
{
	common_game_seed (seed, n_characters);
	log_debug ("game_seed(%ld, %d) done", seed, n_characters);
}

void game_update ()
{
	logic_update (&the_game.map);
	
	int sender;
	
	receive_CtoSmessage (&received, &sender);
	while (received.type != CtoS_NOMSG) {
		switch (received.type) {
			
		case CtoS_INGAME_ACTION:
			logic_intend (&received.action);
			netmessage.type = StoC_INGAME_ACTION;
			netmessage.action = received.action;
			send_StoCmessage (&netmessage, -1);
			break;
			
		case CtoS_INGAME_SETINVENTORY:
			assert((received.character >= 0) && (received.character < MAX_CHARACTERS));
			// TODO: kick client if he doesn't own the player
			Actor* actor = map_get_actor (&the_game.map, received.character);
			memcpy (&actor->character->inventory, &received.inventory, sizeof(Inventory));
			netmessage.type = StoC_INGAME_SETCHARACTER;
			netmessage.who = received.character;
			netmessage.level = actor->level;
			netmessage.hp = actor->hp_max;
			memcpy (&netmessage.inventory, &actor->character->inventory, sizeof(Inventory));
			send_StoCmessage (&netmessage, -1);
			break;

		case CtoS_CHAT:
			netmessage.type = StoC_CHAT;
			strcpy (netmessage.line, received.line);
			send_StoCmessage (&netmessage, -1);
			break;
			
		default:
			log_error ("Received unidentified message type %d from client.",
			           received.type);
			break;
			
		}
		
		receive_CtoSmessage (&received, &sender);
	}
	
	#if 0 && TOWERHACK_DEBUG
	if ((game_time % 300) == 299) {
		netmessage.type = StoC_INGAME_DAMAGE;
		netmessage.damage.time = game_time+20;
		netmessage.damage.where = (Coord) {7,7,0};
		netmessage.damage.attacker = 0;
		netmessage.damage.victim = 0;
		netmessage.damage.weapon = 0;
		netmessage.damage.damage = 10;
		netmessage.damage.hp = 50;
		send_StoCmessage (&netmessage, -1);
	}
	#endif
}

void game_cleanup ()
{
	common_game_cleanup ();
}

void game_damage_handler (int time, Coord where, int attacker, int victim, int weapon, int damage)
{
	log_debug ("Deal %d damage from %d to %d.", damage, attacker, victim);
	
	assert((attacker >= 0) && (attacker < the_game.map.actor.count));
	assert((victim >= 0) && (victim < the_game.map.actor.count));
	
	Actor* actor_victim = map_get_actor (&the_game.map, victim);
	actor_victim->hp -= damage;

	netmessage.type = StoC_INGAME_DAMAGE;
	netmessage.damage.time     = time;
	netmessage.damage.where    = where;
	netmessage.damage.attacker = attacker;
	netmessage.damage.victim   = victim;
	netmessage.damage.weapon   = weapon;
	netmessage.damage.damage   = damage;
	netmessage.damage.hp       = actor_victim->hp;
	send_StoCmessage (&netmessage, -1);
	
	if (actor_victim->hp <= 0) {
		netmessage.type = StoC_INGAME_DIE;
		send_StoCmessage (&netmessage, -1);
	}
}

